Spring MVC起步

处理流程

在请求离开浏览器时,1️⃣:会带有用户所请求内容信息,至少会包含请求的URL。还可能带有其他的信息,例如用户提交的表单信息。

单实例Servlet ,DispatcherServlet将请求委托给应用程序的其他组件来执行实际处理。通过所携带的URL来进行决策。

控制器返回时仅仅传递了一个逻辑名称,这个名字将会用来查找产生结果的真正视图。

搭建Spring MVC

配置DispatcherServlet

传统方式,DispatcherServlet这样的Servlet会配置在web.xml中。但不是唯一的方法。扩展AbstractAnnotationConfigDispatcherServletInitializer的任意类都会自动配置DispatcherServlet和Spring应用上下文。Spring的应用上下文会位于应用程序的Servlet上下文之中。即为dispatchservlet.xml。

在 Servlet3环境中,容器会在类路径中查找实现 javax. servlet.ServletcontainerInitializer接口的类,如果能发现的话,就会用来配置 Servlet容器。Spring提供了这个接口的实现,名为SpringServletcontainerInitializer,这个类反过来又会查找实现 WebApplicationInitializer的类并将配置的任务交给它们来完成。 Spring3.2引入了一个便利的 WebApplicationInitializer基础实现,也就是AbstractAnnotationconfigDispatcherservletInitializer。当扩展了AbstractAnnotationconfigDispatcherServletinitializer,同时也就实现了 WebApplicationInitializer,因此当部署到 Servlet容器中的时候,容器会自动发现它,并用它来配置 Servlet上下文。

两个应用上下文的联系

当DispatcherServlet启动的时候,它会创建Spring应用上下文,并加载配置文件或配置类中所声明的bean。

在Spring Web应用中,通常还会有另外一个应用上下文。另外的这个应用上下文是由ContextLoaderListener创建的。

DispatcherServlet加载包含Web组件的bean,如控制器、视图解析器以及处理器映射,而ContextLoaderListener要加载应用中的其他bean。 这些bean通常是驱动应用后端的中间层和数据层组件。

启用Spring MVC

传统是使用xml,也可以通过config来配置。

编写基本的控制器

@Controller注解与@Component注解实现的效果是一样的,表意性会强一些。

@RequestMapping的属性能够接受一个String类型的数组。

传递模型数据到视图中

将Repository注入Controller。


Model作为参数,方法就能将从Repository中获取的东西填充到模型中。Model实际上就是一个Map,它会传递给视图,这样数据就能渲染到客户端了。当调用addAttribute方法不指定key时,key会根据值的对象类型推断确定。如果希望使用非Spring类型,可以用Map来替代Model。

在返回时统统返回的是jsp的名称。

JSP访问模型:当视图是JSP时,模型数据会作为请求属性放到请求(request)中,所以可以在jsp文件中使用JSTL的标签来渲染列表。

接受请求的输入

Spring MVC允许多种方式将客户端的数据传送到控制器的处理器方法中,包括:

  1. 查询参数(Query Parameter )
  2. 表单参数( Form Parameter )
  3. 路径变量(Path Variable )

处理查询参数

客户端发的请求形如:

通过路径参数接受输入

带有参数的请求尽管可以正常工作,但是从面向资源的角度来看并不理想。
理想情况下,要识别的资源应该通过URL路径进行标示,而不是通过查询参数。对“spittles/ 12345”发起 GET 请求要优于对“ / spittles / show?spitte_id=12345”发起请求。前者能够识别出要查询的资源,而后者描述的是带有参数的一个操作,本质上是通过HTTP发起的RPC。

为了实现路径变量,Spring MVC允许在@RequestMapping路径中添加占位符。占位符的名称要用大括号(“{”和“}”)括起来。路径中的其他部分要与所处理的请求完全匹配,但是占位符部分可以是任意的值。


spittle ()方法会将参数传递到SpittleRepository的findOone ()方法中,用来获取某个Spittle对象,然后将Spittle对象添加到模型中。模型的key将会是spittle,这是根据传递到addAttribute ()方法中的类型推断得到的。

如果传递请求中少量的数据,那查询参数和路径变量是很合适的。通常还需要传递很多的数据(也许是表单提交的数据),查询参数显得有些笨拙和受限了。可以编写控制器方法来处理表单提交。

处理表单

Spring MVC控制器为表单处理提供了良好的支持。使用表单分为两个方面:展现表单以及处理用户通过表单提交的数据。

编写处理表单的控制器

当InternalResourceViewResolver看到视图格式中的“redirect:” 前缀时,就知道要将其解析为重定向的规则,而不是视图的名称。在本例中,它将会重定向到用户基本信息的页面。例如,如果Spitter .username属性的值为“jbauer”, 那么视图将会重定向到“ / spitter / jbauer”.
除了“redirect:”, InternalResourceViewResolver 还能识别“forward:” 前缀。当它发现视图格式中以“forward:” 作为前缀时,请求将会前往(forward) 指定的URL路径,而不再是重定向。

校验表单

与其让校验逻辑弄乱处理器方法,还不如使用Spring对Java校验API 的支持。从Spring 3.0开始,在Spring MVC中提供了对Java校验API的支持。在Spring MVC中要使用Java校验API的话,并不需要什么额外的配置。只要保证在类路径下包含这个Java API的实现,比如Hibernate Validator。



@Valid注解,告知Spring,需要确保这个对象满足校验限制。
如果没有错误的话,Spitter 对象将会通过Repository 进行保存,控制器会像之前那样重定向到基本信息页面。

渲染Web视图

理解视图解析

编写的控制器方法都没有直接产生浏览器中渲染所需的HTML。这些方法只是将一些数据填充到模型中,然后将模型传递给一个用来渲染的视图。这些方法会返回一个String类型的值,这个值是视图的逻辑名称,不会直接引用具体的视图实现。尽管我编写了几个简单的JavaServer Page (JSP) 视图,但是控制器并不关心这些。

将控制器中请求处理的逻辑和视图中的渲染实现解耦是Spring MVC的一个重要特性。控制器只通过逻辑视图名来了解视图,Spring视图解析器来确定使用哪一个视图实现来渲染模型。

Spring MVC定义了一一个名为ViewResolver的接口,


当给resolveViewName(方法传入一个视图名和Locale对象时,它会返回一个View实例。View 是另外一个接口。

View接口的任务就是接受模型以及Servlet 的request 和response对象,并将输出结果渲染到response中。
其中InternalResourceViewResolver只是ViewResolver的实现之一,将视图解析为Web应用的内部资源(一般为JSP)。JSP曾经是,而且现在依然还是Java领域占主导地位的视图技术。

创建JSP视图

Spring 提供了两种支持JSP视图的方式:
1.InternalResourceViewResolver会将视图名解析为JSP文件。另外,如果在JSP页面中使用了JSP 标准标签库( JSTL)的话,InternalResourceViewResolver 能够将视图名解析为JstIView形式的JSP文件,从而将JSTL本地化和资源bundle变量暴露给JSTL的格式化(formatting)和信息( message)标签。
2.Spring提供了两个JSP标签库,一个用于表单到模型的绑定,另一个提供了通用的工具类特性。

配置适用于JSP的视图解析器

InternalResourceViewResolver所采取的方式并不那么直接。它遵循一种约定,会在视图名上添加前缀和后缀,进而确定一个 Web应用中视图资源的物理路径。

解析JSTL视图

如果想让InternalResourceViewResolver将视图解析为JstlView,而不是InternalResourceView的话,只需设置viewClass属性即可:


XML中:

JSTL的格式化标签需要- -个 Locale对象,以便于恰当地格式化地域相关的值,如日期和货币。信息标签可以借助Spring的信息资源和Locale,从而选择适当的信息渲染到HTML之中。通过解析JstlView, JSTL能够获得Locale对象以及Spring中配置的信息资源。

不管使用Java配置还是使用XML,都能确保JSTL的格式化和信息标签能够获得Locale对象以及Spring中配置的信息资源。

使用Spring的JSP库

当为JSP添加功能时,标签库是一种很强大的方式,能够避免在脚本块中直接编写Java代码。Spring 提供了两个JSP标签库,用来帮助定义Spring MVC Web的视图。
其中一个标签库会用来渲染HTML表单标签,这些标签可以绑定model中的某个属性。
另外一个标签库包含了一些工具类标签,随时都可以非常便利地使用它们。

将表单绑定到模型上

Spring的表单绑定JSP标签库包含了14个标签,它们中的大多数都用来渲染HTML中的表单标签。但是,与原生HTML标签的区别在于会绑定模型中的一一个对象,能够根据模型中对象的属性填充值。标签库中还包含了一个为用户展现错误的标签,会将错误信息渲染到最终的HTML之中。


sf:form会渲染会一个HTML
标签,但也会通过commandName属性构建针对某个模型对象的上下文信息。在其他的表单绑定标签中,会引用这个模型对象的属性。模型中必须要有一个key为spitter的对象,否则,表单不能正常渲染(会出现JSP错误)。
如果在模型中Spitter对象的firstName属性值为Jack,那么<sf:input path=“firstName”/> 所渲染的标签中,会存在value=“Jack”。

展现错误

如果存在校验错误的话,请求中会包含错误的详细信息,这些信息是与模型数据放到一起的。所需要做的就是到模型中将这些数据抽取出来,并展现给用户。sf:errors能够让这项任务变得很简单。

Spring通用的标签库

展现国际化

使用Thymeleaf

JSP存在一些缺陷,大多数的JSP模板都是采用HTML的形式,但是又掺杂上了各种JSP标签库的标签,使其变得很混乱。这些标签库能够以便利的方式为JSP带来动态渲染的强大功能,但是也摧毁了维持一个格式良好的文档的可能性。

同时,JSP规范是与Servlet 规范紧密耦合的。这意味着它只能用在基于Servlet 的Web应用之中。JSP 模板不能作为通用的模板(如格式化Email),也不能用于非Servlet的Web应用。

Thymeleaf模板是原生的,不依赖于标签库。能在接受原始HTML的地方进行编辑和渲染。因为没有与Servlet规范耦合,因此Thymeleaf模板能够进人JSP所无法涉足的领域。

配置Thymeleaf视图解析器

为了要在Spring中使用Thymeleaf,我们需要配置三个启用Thymeleaf与Spring集成的bean:
ThymeleafViewResolver:将逻辑视图名称解析为Thymeleaf模板视图;
SpringTemplateEngine:处理模板并渲染结果;
TemplateResolver:加载Thymeleaf模板。


不管使用哪种配置方式,Thymeleaf 都可以将响应中的模板渲染到Spring MVC控制器所处理的请求中。

ThymeleafViewResolver是Spring MVC中ViewResolver的一个实现类。像其他的视图解析器一样, 会接受一个逻辑视图名称,并将其解析为视图。不过在该场景下,视图会是一个Thymeleaf模板。
其中ThymeleafViewResolver中注入了一个对SpringTemplateEngine的引用。SpringTemplateEngine会在Spring中启用Thymeleaf引擎,用来解析模板,并基于这些模板渲染结果。对其注入一个TemplateResolver 的引用。
TemplateResolver会最终定位和查找模板。与之前配置InternalResourceViewResolver类似,使用了prefix和suffix属性。前缀和后缀将会与逻辑视图名组合使用,进而定位Thymeleaf引擎。它的templateMode属性被设置成了HTML5,这表明预期要解析的模板会渲染成HTML5输出。

定义Thymeleaf模板

Thymeleaf在很大程度上就是HTML文件,与JSP不同,没有什么特殊的标签或标签库。Thymeleaf 之所以能够发挥作用,是因为通过自定义的命名空间,为标准的HTML标签集合添加Thymeleaf属性。

借助Thymeleaf实现表单绑定